<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html>
<head>
<title>Java games Pacman</title>
<link rel="stylesheet" href="/cfg/format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="Java, Swing, tutorial, games, Pacman, programming, GUI, multiplatform">
<meta name="description" content="This part of the Java games tutorial presents the Pacman game.">
<meta name="language" content="en">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">

<script type="text/javascript" src="/lib/jquery.js"></script>
<script type="text/javascript" src="/lib/common.js"></script>

</head>

<body>

<div class="container">

<div id="wide_ad" class="ltow">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* 160x600, August 2011 */
google_ad_slot = "2484182563";
google_ad_width = 160;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<div class="content">


<a href="/" title="Home">Home</a>&nbsp;
<a href="..">Contents</a>


<h1>Pacman</h1>


<p>
In this part of the Java 2D games tutorial we will create a simple Pacman game clone.
</p>

<script type="text/javascript"><!--
google_ad_client = "ca-pub-9706709751191532";
/* LargeSquare */
google_ad_slot = "5070696322";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script> 

<p>
Pacman is an arcade game originally developed by a Japanese company <b>Namco</b> in 
1980. Pacman became one of the
most popular arcade games ever. 
</p>


<h2>Development</h2>

<p>
The following code example is a remake of a Pacman game by Brian Postma available 
at <a href="http://javaboutique.internet.com/PacMan/">javaboutique</a>. I have modified 
and simplified the code.
So that it is easier to understand. 
</p>

<p>
The goal of the game is to collect all the points in the maze and avoid the ghosts. 
The pacman is animated in two ways. His position in the maze and his body. We animate 
his body with four images, depending on the direction. The animation is used to create 
the illusion of pacman opening and closing his mouth. The maze consists of 15 x 15 squares.
The structure of the maze is based on a simple array of integers. Pacman has three lives. 
We also count the score. 
</p>


<p>
The game consists of two files.
</p>

<div class="codehead">Board.java</div>
<pre class="code">
package pacman;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Event;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.Timer;


public class Board extends JPanel implements ActionListener {

    Dimension d;
    Font smallfont = new Font("Helvetica", Font.BOLD, 14);

    FontMetrics fmsmall, fmlarge;
    Image ii;
    Color dotcolor = new Color(192, 192, 0);
    Color mazecolor;

    boolean ingame = false;
    boolean dying = false;

    final int blocksize = 24;
    final int nrofblocks = 15;
    final int scrsize = nrofblocks * blocksize;
    final int pacanimdelay = 2;
    final int pacmananimcount = 4;
    final int maxghosts = 12;
    final int pacmanspeed = 6;

    int pacanimcount = pacanimdelay;
    int pacanimdir = 1;
    int pacmananimpos = 0;
    int nrofghosts = 6;
    int pacsleft, score;
    int deathcounter;
    int[] dx, dy;
    int[] ghostx, ghosty, ghostdx, ghostdy, ghostspeed;

    Image ghost;
    Image pacman1, pacman2up, pacman2left, pacman2right, pacman2down;
    Image pacman3up, pacman3down, pacman3left, pacman3right;
    Image pacman4up, pacman4down, pacman4left, pacman4right;

    int pacmanx, pacmany, pacmandx, pacmandy;
    int reqdx, reqdy, viewdx, viewdy;

    final short leveldata[] =
    { 19, 26, 26, 26, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 22,
      21, 0,  0,  0,  17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 20,
      21, 0,  0,  0,  17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 20, 
      21, 0,  0,  0,  17, 16, 16, 24, 16, 16, 16, 16, 16, 16, 20, 
      17, 18, 18, 18, 16, 16, 20, 0,  17, 16, 16, 16, 16, 16, 20,
      17, 16, 16, 16, 16, 16, 20, 0,  17, 16, 16, 16, 16, 24, 20, 
      25, 16, 16, 16, 24, 24, 28, 0,  25, 24, 24, 16, 20, 0,  21, 
      1,  17, 16, 20, 0,  0,  0,  0,  0,  0,  0,  17, 20, 0,  21,
      1,  17, 16, 16, 18, 18, 22, 0,  19, 18, 18, 16, 20, 0,  21,
      1,  17, 16, 16, 16, 16, 20, 0,  17, 16, 16, 16, 20, 0,  21, 
      1,  17, 16, 16, 16, 16, 20, 0,  17, 16, 16, 16, 20, 0,  21,
      1,  17, 16, 16, 16, 16, 16, 18, 16, 16, 16, 16, 20, 0,  21,
      1,  17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 20, 0,  21,
      1,  25, 24, 24, 24, 24, 24, 24, 24, 24, 16, 16, 16, 18, 20,
      9,  8,  8,  8,  8,  8,  8,  8,  8,  8,  25, 24, 24, 24, 28 };

    final int validspeeds[] = { 1, 2, 3, 4, 6, 8 };
    final int maxspeed = 6;

    int currentspeed = 3;
    short[] screendata;
    Timer timer;


    public Board() {

        GetImages();

        addKeyListener(new TAdapter());

        screendata = new short[nrofblocks * nrofblocks];
        mazecolor = new Color(5, 100, 5);
        setFocusable(true);

        d = new Dimension(400, 400);

        setBackground(Color.black);
        setDoubleBuffered(true);

        ghostx = new int[maxghosts];
        ghostdx = new int[maxghosts];
        ghosty = new int[maxghosts];
        ghostdy = new int[maxghosts];
        ghostspeed = new int[maxghosts];
        dx = new int[4];
        dy = new int[4];
        timer = new Timer(40, this);
        timer.start();
    }

    public void addNotify() {
        super.addNotify();
        GameInit();
    }


    public void DoAnim() {
        pacanimcount--;
        if (pacanimcount &lt;= 0) {
            pacanimcount = pacanimdelay;
            pacmananimpos = pacmananimpos + pacanimdir;
            if (pacmananimpos == (pacmananimcount - 1) || pacmananimpos == 0)
                pacanimdir = -pacanimdir;
        }
    }


    public void PlayGame(Graphics2D g2d) {
        if (dying) {
            Death();
        } else {
            MovePacMan();
            DrawPacMan(g2d);
            moveGhosts(g2d);
            CheckMaze();
        }
    }


    public void ShowIntroScreen(Graphics2D g2d) {

        g2d.setColor(new Color(0, 32, 48));
        g2d.fillRect(50, scrsize / 2 - 30, scrsize - 100, 50);
        g2d.setColor(Color.white);
        g2d.drawRect(50, scrsize / 2 - 30, scrsize - 100, 50);

        String s = "Press s to start.";
        Font small = new Font("Helvetica", Font.BOLD, 14);
        FontMetrics metr = this.getFontMetrics(small);

        g2d.setColor(Color.white);
        g2d.setFont(small);
        g2d.drawString(s, (scrsize - metr.stringWidth(s)) / 2, scrsize / 2);
    }


    public void DrawScore(Graphics2D g) {
        int i;
        String s;

        g.setFont(smallfont);
        g.setColor(new Color(96, 128, 255));
        s = "Score: " + score;
        g.drawString(s, scrsize / 2 + 96, scrsize + 16);
        for (i = 0; i &lt; pacsleft; i++) {
            g.drawImage(pacman3left, i * 28 + 8, scrsize + 1, this);
        }
    }


    public void CheckMaze() {
        short i = 0;
        boolean finished = true;

        while (i &lt; nrofblocks * nrofblocks &amp;&amp; finished) {
            if ((screendata[i] &amp; 48) != 0)
                finished = false;
            i++;
        }

        if (finished) {
            score += 50;

            if (nrofghosts &lt; maxghosts)
                nrofghosts++;
            if (currentspeed &lt; maxspeed)
                currentspeed++;
            LevelInit();
        }
    }

    public void Death() {

        pacsleft--;
        if (pacsleft == 0)
            ingame = false;
        LevelContinue();
    }


    public void moveGhosts(Graphics2D g2d) {
        short i;
        int pos;
        int count;

        for (i = 0; i &lt; nrofghosts; i++) {
            if (ghostx[i] % blocksize == 0 &amp;&amp; ghosty[i] % blocksize == 0) {
                pos =
 ghostx[i] / blocksize + nrofblocks * (int)(ghosty[i] / blocksize);

                count = 0;
                if ((screendata[pos] &amp; 1) == 0 &amp;&amp; ghostdx[i] != 1) {
                    dx[count] = -1;
                    dy[count] = 0;
                    count++;
                }
                if ((screendata[pos] &amp; 2) == 0 &amp;&amp; ghostdy[i] != 1) {
                    dx[count] = 0;
                    dy[count] = -1;
                    count++;
                }
                if ((screendata[pos] &amp; 4) == 0 &amp;&amp; ghostdx[i] != -1) {
                    dx[count] = 1;
                    dy[count] = 0;
                    count++;
                }
                if ((screendata[pos] &amp; 8) == 0 &amp;&amp; ghostdy[i] != -1) {
                    dx[count] = 0;
                    dy[count] = 1;
                    count++;
                }
 
                if (count == 0) {
                    if ((screendata[pos] &amp; 15) == 15) {
                        ghostdx[i] = 0;
                        ghostdy[i] = 0;
                    } else {
                        ghostdx[i] = -ghostdx[i];
                        ghostdy[i] = -ghostdy[i];
                    }
                } else {
                    count = (int)(Math.random() * count);
                    if (count > 3)
                        count = 3;
                    ghostdx[i] = dx[count];
                    ghostdy[i] = dy[count];
                }

            }
            ghostx[i] = ghostx[i] + (ghostdx[i] * ghostspeed[i]);
            ghosty[i] = ghosty[i] + (ghostdy[i] * ghostspeed[i]);
            DrawGhost(g2d, ghostx[i] + 1, ghosty[i] + 1);

            if (pacmanx > (ghostx[i] - 12) &amp;&amp; pacmanx &lt; (ghostx[i] + 12) &amp;&amp;
                pacmany > (ghosty[i] - 12) &amp;&amp; pacmany &lt; (ghosty[i] + 12) &amp;&amp;
                ingame) {

                dying = true;
                deathcounter = 64;

            }
        }
    }


    public void DrawGhost(Graphics2D g2d, int x, int y) {
        g2d.drawImage(ghost, x, y, this);
    }


    public void MovePacMan() {
        int pos;
        short ch;

        if (reqdx == -pacmandx &amp;&amp; reqdy == -pacmandy) {
            pacmandx = reqdx;
            pacmandy = reqdy;
            viewdx = pacmandx;
            viewdy = pacmandy;
        }
        if (pacmanx % blocksize == 0 &amp;&amp; pacmany % blocksize == 0) {
            pos =
 pacmanx / blocksize + nrofblocks * (int)(pacmany / blocksize);
            ch = screendata[pos];

            if ((ch &amp; 16) != 0) {
                screendata[pos] = (short)(ch &amp; 15);
                score++;
            }

            if (reqdx != 0 || reqdy != 0) {
                if (!((reqdx == -1 &amp;&amp; reqdy == 0 &amp;&amp; (ch &amp; 1) != 0) ||
                      (reqdx == 1 &amp;&amp; reqdy == 0 &amp;&amp; (ch &amp; 4) != 0) ||
                      (reqdx == 0 &amp;&amp; reqdy == -1 &amp;&amp; (ch &amp; 2) != 0) ||
                      (reqdx == 0 &amp;&amp; reqdy == 1 &amp;&amp; (ch &amp; 8) != 0))) {
                    pacmandx = reqdx;
                    pacmandy = reqdy;
                    viewdx = pacmandx;
                    viewdy = pacmandy;
                }
            }

            // Check for standstill
            if ((pacmandx == -1 &amp;&amp; pacmandy == 0 &amp;&amp; (ch &amp; 1) != 0) ||
                (pacmandx == 1 &amp;&amp; pacmandy == 0 &amp;&amp; (ch &amp; 4) != 0) ||
                (pacmandx == 0 &amp;&amp; pacmandy == -1 &amp;&amp; (ch &amp; 2) != 0) ||
                (pacmandx == 0 &amp;&amp; pacmandy == 1 &amp;&amp; (ch &amp; 8) != 0)) {
                pacmandx = 0;
                pacmandy = 0;
            }
        }
        pacmanx = pacmanx + pacmanspeed * pacmandx;
        pacmany = pacmany + pacmanspeed * pacmandy;
    }


    public void DrawPacMan(Graphics2D g2d) {
        if (viewdx == -1)
            DrawPacManLeft(g2d);
        else if (viewdx == 1)
            DrawPacManRight(g2d);
        else if (viewdy == -1)
            DrawPacManUp(g2d);
        else
            DrawPacManDown(g2d);
    }

    public void DrawPacManUp(Graphics2D g2d) {
        switch (pacmananimpos) {
        case 1:
            g2d.drawImage(pacman2up, pacmanx + 1, pacmany + 1, this);
            break;
        case 2:
            g2d.drawImage(pacman3up, pacmanx + 1, pacmany + 1, this);
            break;
        case 3:
            g2d.drawImage(pacman4up, pacmanx + 1, pacmany + 1, this);
            break;
        default:
            g2d.drawImage(pacman1, pacmanx + 1, pacmany + 1, this);
            break;
        }
    }


    public void DrawPacManDown(Graphics2D g2d) {
        switch (pacmananimpos) {
        case 1:
            g2d.drawImage(pacman2down, pacmanx + 1, pacmany + 1, this);
            break;
        case 2:
            g2d.drawImage(pacman3down, pacmanx + 1, pacmany + 1, this);
            break;
        case 3:
            g2d.drawImage(pacman4down, pacmanx + 1, pacmany + 1, this);
            break;
        default:
            g2d.drawImage(pacman1, pacmanx + 1, pacmany + 1, this);
            break;
        }
    }


    public void DrawPacManLeft(Graphics2D g2d) {
        switch (pacmananimpos) {
        case 1:
            g2d.drawImage(pacman2left, pacmanx + 1, pacmany + 1, this);
            break;
        case 2:
            g2d.drawImage(pacman3left, pacmanx + 1, pacmany + 1, this);
            break;
        case 3:
            g2d.drawImage(pacman4left, pacmanx + 1, pacmany + 1, this);
            break;
        default:
            g2d.drawImage(pacman1, pacmanx + 1, pacmany + 1, this);
            break;
        }
    }


    public void DrawPacManRight(Graphics2D g2d) {
        switch (pacmananimpos) {
        case 1:
            g2d.drawImage(pacman2right, pacmanx + 1, pacmany + 1, this);
            break;
        case 2:
            g2d.drawImage(pacman3right, pacmanx + 1, pacmany + 1, this);
            break;
        case 3:
            g2d.drawImage(pacman4right, pacmanx + 1, pacmany + 1, this);
            break;
        default:
            g2d.drawImage(pacman1, pacmanx + 1, pacmany + 1, this);
            break;
        }
    }


    public void DrawMaze(Graphics2D g2d) {
        short i = 0;
        int x, y;

        for (y = 0; y &lt; scrsize; y += blocksize) {
            for (x = 0; x &lt; scrsize; x += blocksize) {
                g2d.setColor(mazecolor);
                g2d.setStroke(new BasicStroke(2));

                if ((screendata[i] &amp; 1) != 0) // draws left
                {
                    g2d.drawLine(x, y, x, y + blocksize - 1);
                }
                if ((screendata[i] &amp; 2) != 0) // draws top
                {
                    g2d.drawLine(x, y, x + blocksize - 1, y);
                }
                if ((screendata[i] &amp; 4) != 0) // draws right
                {
                    g2d.drawLine(x + blocksize - 1, y, x + blocksize - 1,
                                 y + blocksize - 1);
                }
                if ((screendata[i] &amp; 8) != 0) // draws bottom
                {
                    g2d.drawLine(x, y + blocksize - 1, x + blocksize - 1,
                                 y + blocksize - 1);
                }
                if ((screendata[i] &amp; 16) != 0) // draws point
                {
                    g2d.setColor(dotcolor);
                    g2d.fillRect(x + 11, y + 11, 2, 2);
                }
                i++;
            }
        }
    }

    public void GameInit() {
        pacsleft = 3;
        score = 0;
        LevelInit();
        nrofghosts = 6;
        currentspeed = 3;
    }


    public void LevelInit() {
        int i;
        for (i = 0; i &lt; nrofblocks * nrofblocks; i++)
            screendata[i] = leveldata[i];

        LevelContinue();
    }


    public void LevelContinue() {
        short i;
        int dx = 1;
        int random;

        for (i = 0; i &lt; nrofghosts; i++) {
            ghosty[i] = 4 * blocksize;
            ghostx[i] = 4 * blocksize;
            ghostdy[i] = 0;
            ghostdx[i] = dx;
            dx = -dx;
            random = (int)(Math.random() * (currentspeed + 1));
            if (random > currentspeed)
                random = currentspeed;
            ghostspeed[i] = validspeeds[random];
        }

        pacmanx = 7 * blocksize;
        pacmany = 11 * blocksize;
        pacmandx = 0;
        pacmandy = 0;
        reqdx = 0;
        reqdy = 0;
        viewdx = -1;
        viewdy = 0;
        dying = false;
    }

    public void GetImages()
    {

      ghost = new ImageIcon(Board.class.getResource("../pacpix/ghost.png")).getImage();
      pacman1 = new ImageIcon(Board.class.getResource("../pacpix/pacman.png")).getImage();
      pacman2up = new ImageIcon(Board.class.getResource("../pacpix/up1.png")).getImage();
      pacman3up = new ImageIcon(Board.class.getResource("../pacpix/up2.png")).getImage();
      pacman4up = new ImageIcon(Board.class.getResource("../pacpix/up3.png")).getImage();
      pacman2down = new ImageIcon(Board.class.getResource("../pacpix/down1.png")).getImage();
      pacman3down = new ImageIcon(Board.class.getResource("../pacpix/down2.png")).getImage(); 
      pacman4down = new ImageIcon(Board.class.getResource("../pacpix/down3.png")).getImage();
      pacman2left = new ImageIcon(Board.class.getResource("../pacpix/left1.png")).getImage();
      pacman3left = new ImageIcon(Board.class.getResource("../pacpix/left2.png")).getImage();
      pacman4left = new ImageIcon(Board.class.getResource("../pacpix/left3.png")).getImage();
      pacman2right = new ImageIcon(Board.class.getResource("../pacpix/right1.png")).getImage();
      pacman3right = new ImageIcon(Board.class.getResource("../pacpix/right2.png")).getImage();
      pacman4right = new ImageIcon(Board.class.getResource("../pacpix/right3.png")).getImage();

    }

    public void paint(Graphics g)
    {
      super.paint(g);

      Graphics2D g2d = (Graphics2D) g;

      g2d.setColor(Color.black);
      g2d.fillRect(0, 0, d.width, d.height);

      DrawMaze(g2d);
      DrawScore(g2d);
      DoAnim();
      if (ingame)
        PlayGame(g2d);
      else
        ShowIntroScreen(g2d);

      g.drawImage(ii, 5, 5, this);
      Toolkit.getDefaultToolkit().sync();
      g.dispose();
    }

    class TAdapter extends KeyAdapter {
        public void keyPressed(KeyEvent e) {

          int key = e.getKeyCode();

          if (ingame)
          {
            if (key == KeyEvent.VK_LEFT)
            {
              reqdx=-1;
              reqdy=0;
            }
            else if (key == KeyEvent.VK_RIGHT)
            {
              reqdx=1;
              reqdy=0;
            }
            else if (key == KeyEvent.VK_UP)
            {
              reqdx=0;
              reqdy=-1;
            }
            else if (key == KeyEvent.VK_DOWN)
            {
              reqdx=0;
              reqdy=1;
            }
            else if (key == KeyEvent.VK_ESCAPE &amp;&amp; timer.isRunning())
            {
              ingame=false;
            }
            else if (key == KeyEvent.VK_PAUSE) {
                if (timer.isRunning())
                    timer.stop();
                else timer.start();
            }
          }
          else
          {
            if (key == 's' || key == 'S')
          {
              ingame=true;
              GameInit();
            }
          }
      }

          public void keyReleased(KeyEvent e) {
              int key = e.getKeyCode();

              if (key == Event.LEFT || key == Event.RIGHT || 
                 key == Event.UP ||  key == Event.DOWN)
              {
                reqdx=0;
                reqdy=0;
              }
          }
      }

    public void actionPerformed(ActionEvent e) {
        repaint();  
    }
}
</pre>

<p>
The Commons.java file has some common constants. 
</p>


<pre class="explanation">
final short leveldata[] =
{ 19, 26, 26, 26, 18, ... };
</pre>

<p>
These numbers make up the maze. They provide information out of which we create the corners
and the points. For example number 19 in the upper left corner means, that the square will have 
top and left borders and a point. (16  + 2 + 1) 
</p>


<pre class="explanation">
 public void doAnim() {
     pacanimcount--;
     if (pacanimcount &lt;= 0) {
         pacanimcount = pacanimdelay;
         pacmananimpos = pacmananimpos + pacanimdir;
         if (pacmananimpos == (pacmananimcount - 1) || pacmananimpos == 0)
             pacanimdir = -pacanimdir;
     }
 }
</pre>

<p>
The doAnim() counts the pacmananimpos variable, which determines what pacman image is 
drawn. There are four pacman images. There is also a 
pacanimdelay variable, which makes the animation a bit slower. Otherwise 
the pacman would open his mouth too fast.  
</p>


<pre class="explanation">
boolean finished = true;

while (i &lt; nrofblocks * nrofblocks &amp;&amp; finished) {
    if ((screendata[i] &amp; 16) != 0)
        finished = false;
    i++;
}
</pre>

<p>
This code is part of the checkMaze() method. It checks, 
if there are any points left for the Pacman to eat. Number 16 stands for a point. 
If all points are consumed, we move to the next level. 
</p>

<p>
Next we will examine the moveGhosts() method. The ghosts move one square and then decide, 
if they change the direction. 
</p>

<pre class="explanation">
if (ghostx[i] % blocksize == 0 &amp;&amp; ghosty[i] % blocksize == 0) {
</pre>

<p>
Continue only if you have finished moving one square.
</p>

<pre class="explanation">
pos = ghostx[i] / blocksize + nrofblocks * (int)(ghosty[i] / blocksize);
</pre>

<p>
This line determines, where the ghost is situated. In which position/square. 
There are 225 theoretical positions. 
(A ghost cannot move over walls. )
</p>

<pre class="explanation">
if ((screendata[pos] &amp; 1) == 0 &amp;&amp; ghostdx[i] != 1) {
    dx[count] = -1;
    dy[count] = 0;
    count++;
}
</pre>

<p>
If there is no obstacle on the left and the ghost is not already moving to the right, 
the ghost will move to the left. What does this code really mean? If the ghost enters a 
tunnel, he will continue in the same direction until he is out of the tunnel. Moving of 
ghosts is partly random. We do not apply this randomness inside long tunnels. 
The ghost might get stuck there. 
</p>

<pre class="explanation">
if (pacmanx > (ghostx[i] - 12) &amp;&amp; pacmanx &lt; (ghostx[i] + 12) &amp;&amp;
    pacmany > (ghosty[i] - 12) &amp;&amp; pacmany &lt; (ghosty[i] + 12) &amp;&amp;
    ingame) {

    dying = true;
    deathcounter = 64;
}
</pre>

<p>
If there is a collision between ghosts and a pacman, the pacman dies. 
</p>

<p>
Next we are going to examine the movePacman() method. The reqdx and reqdy variables 
are determined in the TAdapter inner class. These variables are controlled with cursor keys. 
</p>

<pre class="explanation">
if ((ch &amp; 16) != 0) {
    screendata[pos] = (short)(ch &amp; 15);
    score++;
}
</pre>

<p>
If the pacman moves to a position, where there is a point, we remove it from 
the maze and increase the score value.
</p>

<pre class="explanation">
if ((pacmandx == -1 &amp;&amp; pacmandy == 0 &amp;&amp; (ch &amp; 1) != 0) ||
    (pacmandx == 1 &amp;&amp; pacmandy == 0 &amp;&amp; (ch &amp; 4) != 0) ||
    (pacmandx == 0 &amp;&amp; pacmandy == -1 &amp;&amp; (ch &amp; 2) != 0) ||
    (pacmandx == 0 &amp;&amp; pacmandy == 1 &amp;&amp; (ch &amp; 8) != 0)) {
    pacmandx = 0;
    pacmandy = 0;
}
</pre>

<p>
If the pacman cannot move further it his current direction, there is a standstill. 
</p>

<pre class="explanation">
public void drawPacMan(Graphics2D g2d) {
    if (viewdx == -1)
        drawPacManLeft(g2d);
    else if (viewdx == 1)
        drawPacManRight(g2d);
    else if (viewdy == -1)
        drawPacManUp(g2d);
    else
        drawPacManDown(g2d);
}
</pre>

<p>
There are four possible directions for a pacman. There are four images for all directions. 
The images are used to animate pacman opening a closing his mouth.
</p>

<p>
The drawMaze() method draws the maze out of the numbers in the screendata array. Number 1 is a left 
border, 2 is a top border, 4 is a right border, 8 is a bottom border and 16 is a point. 
We simply go through all 225 squares int the maze. For example we have 9 in the 
screendata array. We have the first bit (1) and the fourth bit (8) set. So we draw a 
bottom and a left border on this particular square. 
</p>

<pre class="explanation">
if ((screendata[i] &amp; 1) != 0) // draws left
{
    g2d.drawLine(x, y, x, y + blocksize - 1);
}
</pre>

<p>
Draw a left border if the first bit of a number is set.  
</p>

<div class="codehead">PacMan.java</div>
<pre class="code">
package packman;

import javax.swing.JFrame;

import pacman.Board;


public class PacMan extends JFrame
{

  public PacMan()
  {
    add(new Board());
    setTitle("Pacman");
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setSize(380, 420);
    setLocationRelativeTo(null);
    setVisible(true);
  }

  public static void main(String[] args) {
      new PacMan();
  }
}
</pre>

<p>
This is a PacMan file with a main method. 
</p>


<img src="/img/gfx/javagames/pacman.png" alt="Pacman">
<div class="figure">Figure: Pacman</div>

<p>
This was the Pacman game.
</p>


<div class="center"> 
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script> 
</div> 
<br>


<div class="botNav, center">
<span class="botNavItem"><a href="/">Home</a></span> ‡ <span class="botNavItem"><a href="..">Contents</a></span> ‡ 
<span class="botNavItem"><a href="#">Top of Page</a></span>
</div>


<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified September 27, 2008  <span class="copyright">&copy; 2007 - 2013 Jan Bodnar</span>
</div>
</div>

</div> <!-- content -->

</div> <!-- container -->

</body>
</html>
